using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Base
{
#pragma warning disable 8500

    /// <summary>
    /// Span扩展类
    /// </summary>
    unsafe public static partial class SpanEx
    {
        /// <summary>
        /// 将Span数据转移为按行存放的文件
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="span">Span数据</param>
        /// <returns>按行存放的文件</returns>
#if NET4_0
        public static string ToString<T>(this Span<T> span) where T : struct
#else
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static string ToString<T>(in this Span<T> span) where T : struct
#endif        
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < span.Length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.AppendLine();
                }

                sb.Append(span[i].ToString());
            }

            return sb.ToString();
        }





        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="value">查找的值</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(this Span<T> data, T value) where T : struct, IComparable<T>
        {
            if (data.Length <= 0)
            {
                return -1;
            }

            int leftIndex = 0;
            int rightIndex = data.Length - 1;
            int index, comparerResult;

            while (leftIndex <= rightIndex)
            {
                index = GetMedian(leftIndex, rightIndex);
                comparerResult = data[index].CompareTo(value);
                if (comparerResult == 0)
                {
                    return index;
                }
                else if (comparerResult < 0)
                {
                    leftIndex = index + 1;
                }
                else
                {
                    rightIndex = index - 1;
                }
            }

            return ~leftIndex;
        }

        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="value">查找的值</param>
        /// <param name="comparer">自定义比较器,当为null时使用默认比较器</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(this Span<T> data, T value, IComparer<T> comparer) where T : struct
        {
            if (data.Length <= 0)
            {
                return -1;
            }

            int leftIndex = 0;
            int rightIndex = data.Length - 1;
            int index, comparerResult;

            if (comparer == null)
            {
                IComparer comparer2 = Comparer.Default;
                while (leftIndex <= rightIndex)
                {
                    index = GetMedian(leftIndex, rightIndex);
                    comparerResult = comparer2.Compare(data[index], value);
                    if (comparerResult == 0)
                    {
                        return index;
                    }
                    else if (comparerResult < 0)
                    {
                        leftIndex = index + 1;
                    }
                    else
                    {
                        rightIndex = index - 1;
                    }
                }
            }
            else
            {
                while (leftIndex <= rightIndex)
                {
                    index = GetMedian(leftIndex, rightIndex);
                    comparerResult = comparer.Compare(data[index], value);
                    if (comparerResult == 0)
                    {
                        return index;
                    }
                    else if (comparerResult < 0)
                    {
                        leftIndex = index + 1;
                    }
                    else
                    {
                        rightIndex = index - 1;
                    }
                }
            }

            return ~leftIndex;
        }


        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="value">查找的值</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(this SpanZ<T> data, T value) where T : struct, IComparable<T>
        {
            return BinarySearch<T>(data.DataPtr, data.Length, value);
        }

        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="value">查找的值</param>
        /// <param name="comparer">自定义比较器,当为null时使用默认比较器</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(this SpanZ<T> data, T value, IComparer<T> comparer) where T : struct
        {
            return BinarySearch<T>(data.DataPtr, data.Length, value, comparer);
        }




        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据指针</param>
        /// <param name="length">数据长度</param>
        /// <param name="value">查找的值</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(T* data, int length, T value) where T : struct, IComparable<T>
        {
            if (length <= 0)
            {
                return -1;
            }

            int leftIndex = 0;
            int rightIndex = length - 1;
            int index, comparerResult;

            while (leftIndex <= rightIndex)
            {
                index = GetMedian(leftIndex, rightIndex);
                comparerResult = data[index].CompareTo(value);
                if (comparerResult == 0)
                {
                    return index;
                }
                else if (comparerResult < 0)
                {
                    leftIndex = index + 1;
                }
                else
                {
                    rightIndex = index - 1;
                }
            }

            return ~leftIndex;
        }

        /// <summary>
        /// 二分查找指定值索引,数据长度小于0或未找到返回-1,找到返回指定值所在索引
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据指针</param>
        /// <param name="length">数据长度</param>
        /// <param name="value">查找的值</param>
        /// <param name="comparer">自定义比较器,当为null时使用默认比较器</param>
        /// <returns>数据长度小于0或未找到返回-1,找到返回指定值所在索引</returns>
        public static int BinarySearch<T>(T* data, int length, T value, IComparer<T> comparer) where T : struct
        {
            if (length <= 0)
            {
                return -1;
            }

            int leftIndex = 0;
            int rightIndex = length - 1;
            int index, comparerResult;

            if (comparer == null)
            {
                IComparer comparer2 = Comparer.Default;
                while (leftIndex <= rightIndex)
                {
                    index = GetMedian(leftIndex, rightIndex);
                    comparerResult = comparer2.Compare(data[index], value);
                    if (comparerResult == 0)
                    {
                        return index;
                    }
                    else if (comparerResult < 0)
                    {
                        leftIndex = index + 1;
                    }
                    else
                    {
                        rightIndex = index - 1;
                    }
                }
            }
            else
            {
                while (leftIndex <= rightIndex)
                {
                    index = GetMedian(leftIndex, rightIndex);
                    comparerResult = comparer.Compare(data[index], value);
                    if (comparerResult == 0)
                    {
                        return index;
                    }
                    else if (comparerResult < 0)
                    {
                        leftIndex = index + 1;
                    }
                    else
                    {
                        rightIndex = index - 1;
                    }
                }
            }

            return ~leftIndex;
        }





#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        private static int GetMedian(int low, int hi)
        {
            //// Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
            //Debug.Assert(low <= hi);
            //Debug.Assert(hi - low >= 0, "Length overflow!");
            return low + ((hi - low) >> 1);
        }

    }
}
